home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / graph+ / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-03-01  |  56.7 KB

  1. Path: mirror!adelie!necntc!husc6!seismo!munnari!sources-request
  2. From: sources-request@munnari.oz
  3. Newsgroups: mod.sources
  4. Subject: v08i082:  Graph+, A Graph Plotting Program, Part02/03
  5. Message-ID: <1432@munnari.oz>
  6. Date: 28 Feb 87 07:36:59 GMT
  7. Sender: kre@munnari.oz
  8. Lines: 2448
  9. Approved: kre@munnari.oz.au
  10.  
  11. Submitted by: Alan Kent <ajk@goanna.oz.au>
  12. Mod.sources: Volume 8, Issue 82
  13. Archive-name: graph+/Part02
  14.  
  15. #! /bin/sh
  16. # This is a shell archive, meaning:
  17. # 1.  Remove everything above the #! /bin/sh line.
  18. # 2.  Save the resulting test in a file
  19. # 3.  Execute the file with /bin/sh (not csh) to create the files:
  20. #
  21. #        abort.c
  22. #        adjacent.c
  23. #        appendtb.c
  24. #        attrnode.c
  25. #        average.c
  26. #        count.c
  27. #        cpyentry.c
  28. #        cpytable.c
  29. #        cumulate.c
  30. #        dumpgrph.c
  31. #        eval.c
  32. #        evaltab.c
  33. #        freetab.c
  34. #        fundeclr.c
  35. #
  36. # Created by ajk on Wed Feb 25 09:24:11 EST 1987
  37. #
  38. if test -f 'abort.c'
  39. then
  40.     echo shar: will not over-write existing file "'abort.c'"
  41. else
  42. echo extracting "'abort.c'"
  43. sed 's/^X//' >abort.c <<'SHAR_EOF'
  44. X/*
  45. X * Copyright (C) 1986   Alan Kent
  46. X *
  47. X * Permission is granted to freely distribute part or
  48. X * all of this code as long as it is not for profit
  49. X * and this message is retained in the code.
  50. X *
  51. X * No resposibility is taken for any damage or incorect
  52. X * results this program generates.
  53. X * 
  54. X */
  55. X
  56. X
  57. X#include <stdio.h>
  58. X
  59. Xextern int linenum;
  60. Xextern char *infilename;
  61. Xextern int warnings;
  62. X
  63. X
  64. X
  65. Xabort ( mesg , parm )
  66. Xchar *mesg , *parm;
  67. X{
  68. X    fprintf ( stderr , "%s: near line %d: " , infilename , linenum );
  69. X    fprintf ( stderr , mesg , parm );
  70. X    fprintf ( stderr , "\n" );
  71. X    while ( yyinput () > 0 );    /* read until EOF */
  72. X    exit ( 1 );
  73. X}
  74. X
  75. X
  76. Xwarn ( mesg , parm )
  77. Xchar *mesg , *parm;
  78. X{
  79. X    if ( warnings ) {
  80. X    fprintf ( stderr , "%s: warning near line %d: " , infilename , linenum );
  81. X    fprintf ( stderr , mesg , parm );
  82. X    fprintf ( stderr , "\n" );
  83. X    }
  84. X}
  85. X
  86. SHAR_EOF
  87. if test 850 -ne "`wc -c < 'abort.c'`"
  88. then
  89.     echo shar: error transmitting "'abort.c'" '(should have been 850 characters)'
  90. fi
  91. fi
  92. if test -f 'adjacent.c'
  93. then
  94.     echo shar: will not over-write existing file "'adjacent.c'"
  95. else
  96. echo extracting "'adjacent.c'"
  97. sed 's/^X//' >adjacent.c <<'SHAR_EOF'
  98. X/*
  99. X * Copyright (C) 1986   Alan Kent
  100. X *
  101. X * Permission is granted to freely distribute part or
  102. X * all of this code as long as it is not for profit
  103. X * and this message is retained in the code.
  104. X *
  105. X * No resposibility is taken for any damage or incorect
  106. X * results this program generates.
  107. X * 
  108. X */
  109. X
  110. X
  111. X#include <stdio.h>
  112. X#include "graph.h"
  113. X
  114. X
  115. Xtable_st *
  116. Xadjacent ( tab1 , tab2 )
  117. Xtable_st *tab1 , *tab2;
  118. X{
  119. X    table_st *p;
  120. X    table_st *final;
  121. X
  122. X    if ( tab1 == NULL ) {
  123. X    final = tab2;
  124. X    }
  125. X    else if ( tab2 == NULL ) {
  126. X    final = tab1;
  127. X    }
  128. X    else {
  129. X    if ( tab1->size != tab2->size ) {
  130. X        abort ( "ADJACENT: Cannot join tables of different length" );
  131. X    }
  132. X    else {
  133. X        for ( p = tab1; p->next != NULL; p = p->next );
  134. X        p->next = tab2;
  135. X        final = tab1;
  136. X    }
  137. X    }
  138. X    return ( final );
  139. X}
  140. SHAR_EOF
  141. if test 785 -ne "`wc -c < 'adjacent.c'`"
  142. then
  143.     echo shar: error transmitting "'adjacent.c'" '(should have been 785 characters)'
  144. fi
  145. fi
  146. if test -f 'appendtb.c'
  147. then
  148.     echo shar: will not over-write existing file "'appendtb.c'"
  149. else
  150. echo extracting "'appendtb.c'"
  151. sed 's/^X//' >appendtb.c <<'SHAR_EOF'
  152. X/*
  153. X * Copyright (C) 1986   Alan Kent
  154. X *
  155. X * Permission is granted to freely distribute part or
  156. X * all of this code as long as it is not for profit
  157. X * and this message is retained in the code.
  158. X *
  159. X * No resposibility is taken for any damage or incorect
  160. X * results this program generates.
  161. X * 
  162. X */
  163. X
  164. X
  165. X#include <stdio.h>
  166. X#include "graph.h"
  167. X
  168. X
  169. Xextern table_st *new_table ();
  170. X
  171. X
  172. Xtable_st *
  173. Xappend_tables ( tab1 , tab2 )
  174. Xtable_st *tab1 , *tab2;
  175. X{
  176. X    register table_st *p1 , *p2;
  177. X    table_st *newtab;
  178. X    int count;
  179. X    int i;
  180. X
  181. X
  182. X    if ( tab1 == NULL )
  183. X    return ( tab2 );
  184. X    if ( tab2 == NULL )
  185. X    return ( tab1 );
  186. X    p1 = tab1;
  187. X    p2 = tab2;
  188. X    count = 0;
  189. X    while ( p1 != NULL  &&  p2 != NULL ) {
  190. X    p1 = p1->next;
  191. X    p2 = p2->next;
  192. X    count++;
  193. X    }
  194. X    if ( p1 != NULL  ||  p2 != NULL )
  195. X    abort ( "Tables must be of same width to append them" );
  196. X    newtab = new_table ( count , tab1->size + tab2->size );
  197. X    for ( p1 = tab1, p2 = newtab; p1 != NULL; p1 = p1->next, p2 = p2->next )
  198. X    for ( i = 0; i < tab1->size; i++ )
  199. X        p2->data[i] = p1->data[i];
  200. X    for ( p1 = tab2, p2 = newtab; p1 != NULL; p1 = p1->next, p2 = p2->next )
  201. X    for ( i = 0; i < tab2->size; i++ )
  202. X        p2->data[i+tab1->size] = p1->data[i];
  203. X    free_table ( tab1 );
  204. X    free_table ( tab2 );
  205. X    return ( newtab );
  206. X}
  207. X
  208. SHAR_EOF
  209. if test 1271 -ne "`wc -c < 'appendtb.c'`"
  210. then
  211.     echo shar: error transmitting "'appendtb.c'" '(should have been 1271 characters)'
  212. fi
  213. fi
  214. if test -f 'attrnode.c'
  215. then
  216.     echo shar: will not over-write existing file "'attrnode.c'"
  217. else
  218. echo extracting "'attrnode.c'"
  219. sed 's/^X//' >attrnode.c <<'SHAR_EOF'
  220. X/*
  221. X * Copyright (C) 1986   Alan Kent
  222. X *
  223. X * Permission is granted to freely distribute part or
  224. X * all of this code as long as it is not for profit
  225. X * and this message is retained in the code.
  226. X *
  227. X * No resposibility is taken for any damage or incorect
  228. X * results this program generates.
  229. X * 
  230. X */
  231. X
  232. X
  233. X#include <stdio.h>
  234. X#include "graph.h"
  235. X
  236. Xextern char *new ();
  237. X
  238. X/* create an attribute expression node */
  239. X
  240. Xattr_st *
  241. Xattr_node ( node_type , value , left , right )
  242. Xint node_type;
  243. Xdouble value;
  244. Xattr_st *left , *right;
  245. X{
  246. X    attr_st *p;
  247. X
  248. X    p = (attr_st *) new ( sizeof ( attr_st ) );
  249. X    p->node_type = node_type;
  250. X    p->value = value;
  251. X    p->left = left;
  252. X    p->right = right;
  253. X    return ( p );
  254. X}
  255. X
  256. SHAR_EOF
  257. if test 691 -ne "`wc -c < 'attrnode.c'`"
  258. then
  259.     echo shar: error transmitting "'attrnode.c'" '(should have been 691 characters)'
  260. fi
  261. fi
  262. if test -f 'average.c'
  263. then
  264.     echo shar: will not over-write existing file "'average.c'"
  265. else
  266. echo extracting "'average.c'"
  267. sed 's/^X//' >average.c <<'SHAR_EOF'
  268. X/*
  269. X * Copyright (C) 1986   Alan Kent
  270. X *
  271. X * Permission is granted to freely distribute part or
  272. X * all of this code as long as it is not for profit
  273. X * and this message is retained in the code.
  274. X *
  275. X * No resposibility is taken for any damage or incorect
  276. X * results this program generates.
  277. X * 
  278. X */
  279. X
  280. X
  281. X#include <stdio.h>
  282. X#include "graph.h"
  283. X
  284. X
  285. Xdouble
  286. Xaverage_fun ( table , from , to )
  287. Xtable_st *table;
  288. Xint from , to;
  289. X{
  290. X    int i;
  291. X    double val;
  292. X
  293. X    if ( table == NULL )
  294. X    abort ( "AVERAGE requires at least a single column table" );
  295. X    if ( table->size < 1 ) {
  296. X    warn ( "AVERAGE requires at least one value in table " );
  297. X    return ( 0.0 );
  298. X    }
  299. X    if ( to >= table->size )
  300. X    to = table->size - 1;
  301. X    val = 0.0;
  302. X    for ( i = from; i <= to; i++ )
  303. X    val += table->data[i];
  304. X    return ( val / (double)( to - from + 1 ) );
  305. X}
  306. X
  307. SHAR_EOF
  308. if test 813 -ne "`wc -c < 'average.c'`"
  309. then
  310.     echo shar: error transmitting "'average.c'" '(should have been 813 characters)'
  311. fi
  312. fi
  313. if test -f 'count.c'
  314. then
  315.     echo shar: will not over-write existing file "'count.c'"
  316. else
  317. echo extracting "'count.c'"
  318. sed 's/^X//' >count.c <<'SHAR_EOF'
  319. X/*
  320. X * Copyright (C) 1986   Alan Kent
  321. X *
  322. X * Permission is granted to freely distribute part or
  323. X * all of this code as long as it is not for profit
  324. X * and this message is retained in the code.
  325. X *
  326. X * No resposibility is taken for any damage or incorect
  327. X * results this program generates.
  328. X * 
  329. X */
  330. X
  331. X
  332. X#include <stdio.h>
  333. X#include "graph.h"
  334. X
  335. X
  336. Xdouble
  337. Xcount_fun ( table , from , to )
  338. Xtable_st *table;
  339. X{
  340. X    if ( table == NULL )
  341. X    return ( 0.0 );
  342. X    if ( to >= table->size )
  343. X    to = table->size - 1;
  344. X    if ( from > to )
  345. X    return ( 0.0 );
  346. X    return ( (double) to - from + 1 );
  347. X}
  348. X
  349. SHAR_EOF
  350. if test 567 -ne "`wc -c < 'count.c'`"
  351. then
  352.     echo shar: error transmitting "'count.c'" '(should have been 567 characters)'
  353. fi
  354. fi
  355. if test -f 'cpyentry.c'
  356. then
  357.     echo shar: will not over-write existing file "'cpyentry.c'"
  358. else
  359. echo extracting "'cpyentry.c'"
  360. sed 's/^X//' >cpyentry.c <<'SHAR_EOF'
  361. X/*
  362. X * Copyright (C) 1986   Alan Kent
  363. X *
  364. X * Permission is granted to freely distribute part or
  365. X * all of this code as long as it is not for profit
  366. X * and this message is retained in the code.
  367. X *
  368. X * No resposibility is taken for any damage or incorect
  369. X * results this program generates.
  370. X * 
  371. X */
  372. X
  373. X
  374. X#include <stdio.h>
  375. X#include "graph.h"
  376. X
  377. Xcopy_entry ( table , to , from )
  378. Xtable_st *table;
  379. Xint to , from;
  380. X{
  381. X    table_st *p;
  382. X
  383. X    for ( p = table; p != NULL; p = p->next )
  384. X    p->data[to] = p->data[from];
  385. X}
  386. X
  387. SHAR_EOF
  388. if test 498 -ne "`wc -c < 'cpyentry.c'`"
  389. then
  390.     echo shar: error transmitting "'cpyentry.c'" '(should have been 498 characters)'
  391. fi
  392. fi
  393. if test -f 'cpytable.c'
  394. then
  395.     echo shar: will not over-write existing file "'cpytable.c'"
  396. else
  397. echo extracting "'cpytable.c'"
  398. sed 's/^X//' >cpytable.c <<'SHAR_EOF'
  399. X/*
  400. X * Copyright (C) 1986   Alan Kent
  401. X *
  402. X * Permission is granted to freely distribute part or
  403. X * all of this code as long as it is not for profit
  404. X * and this message is retained in the code.
  405. X *
  406. X * No resposibility is taken for any damage or incorect
  407. X * results this program generates.
  408. X * 
  409. X */
  410. X
  411. X
  412. X#include <stdio.h>
  413. X#include "graph.h"
  414. X
  415. X
  416. Xextern table_st *new_table ();
  417. X
  418. X
  419. Xtable_st *
  420. Xcopy_of_table ( oldtab )
  421. Xtable_st *oldtab;
  422. X{
  423. X    int i;
  424. X    register table_st *table , *ftp , *ttp;
  425. X
  426. X    if ( oldtab == NULL )
  427. X    return ( NULL );
  428. X    table = new_table ( num_cols ( oldtab ) , oldtab->size );
  429. X    ftp = oldtab;
  430. X    ttp = table;
  431. X    while ( ftp != NULL ) {
  432. X    for ( i = 0; i < table->size; i++ )
  433. X        ttp->data[i] = ftp->data[i];
  434. X    ftp = ftp->next;
  435. X    ttp = ttp->next;
  436. X    }
  437. X    return ( table );
  438. X}
  439. SHAR_EOF
  440. if test 786 -ne "`wc -c < 'cpytable.c'`"
  441. then
  442.     echo shar: error transmitting "'cpytable.c'" '(should have been 786 characters)'
  443. fi
  444. fi
  445. if test -f 'cumulate.c'
  446. then
  447.     echo shar: will not over-write existing file "'cumulate.c'"
  448. else
  449. echo extracting "'cumulate.c'"
  450. sed 's/^X//' >cumulate.c <<'SHAR_EOF'
  451. X/*
  452. X * Copyright (C) 1986   Alan Kent
  453. X *
  454. X * Permission is granted to freely distribute part or
  455. X * all of this code as long as it is not for profit
  456. X * and this message is retained in the code.
  457. X *
  458. X * No resposibility is taken for any damage or incorect
  459. X * results this program generates.
  460. X * 
  461. X */
  462. X
  463. X
  464. X#include <stdio.h>
  465. X#include <math.h>
  466. X#include "graph.h"
  467. X#include "y.tab.h"
  468. X
  469. X
  470. X
  471. X
  472. Xtable_st *
  473. Xcumulate ( table , attr )
  474. Xtable_st *table;
  475. Xint attr;
  476. X{
  477. X    double total;
  478. X    double *data;
  479. X    int i;
  480. X    table_st *p;
  481. X
  482. X    total = 0.0;
  483. X    p = table;
  484. X    if ( attr < 1 )
  485. X    abort ( "Cannot CUMULATE on column $0" );
  486. X    while ( --attr > 0  &&  p != NULL )
  487. X    p = p->next;
  488. X    if ( p == NULL )
  489. X    abort ( "Illegal column to CUMULATE by" );
  490. X    data = p->data;
  491. X    for ( i = 0; i < p->size; i++ ) {
  492. X    total += data[i];
  493. X    data[i] = total;
  494. X    }
  495. X    return ( table );
  496. X}
  497. X
  498. SHAR_EOF
  499. if test 845 -ne "`wc -c < 'cumulate.c'`"
  500. then
  501.     echo shar: error transmitting "'cumulate.c'" '(should have been 845 characters)'
  502. fi
  503. fi
  504. if test -f 'dumpgrph.c'
  505. then
  506.     echo shar: will not over-write existing file "'dumpgrph.c'"
  507. else
  508. echo extracting "'dumpgrph.c'"
  509. sed 's/^X//' >dumpgrph.c <<'SHAR_EOF'
  510. X/*
  511. X * Copyright (C) 1986   Alan Kent
  512. X *
  513. X * Permission is granted to freely distribute part or
  514. X * all of this code as long as it is not for profit
  515. X * and this message is retained in the code.
  516. X *
  517. X * No resposibility is taken for any damage or incorect
  518. X * results this program generates.
  519. X * 
  520. X */
  521. X
  522. X/*
  523. X * WARNING: This file is extremely sensative to changes.
  524. X *    Making one minor change may break other features.
  525. X *       This file probably needs to be re-written.
  526. X */
  527. X
  528. X#include <stdio.h>
  529. X#include <math.h>
  530. X#include "graph.h"
  531. X#include "y.tab.h"
  532. X
  533. X
  534. X#define DEBUG        0
  535. X#define DEBUG_LOG    0
  536. X
  537. X
  538. X/* this info is for trying to place the text nicely on the screen */
  539. X/* however, unfortunately it is different for all the different plotters! */
  540. X
  541. X#ifdef  LASER
  542. X#define CHAR_WIDTH    48
  543. X#define CHAR_HEIGHT    100
  544. X#else
  545. X#define CHAR_WIDTH    80
  546. X#define CHAR_HEIGHT    100
  547. X#endif
  548. X
  549. X
  550. X#define XSPACE        4096
  551. X#define YSPACE        4096
  552. X#define XORIGIN        (15*CHAR_WIDTH)
  553. X#define YORIGIN        650
  554. X#define XRANGE        (XSPACE-XORIGIN)
  555. X#define YRANGE        (YSPACE-YORIGIN-3*CHAR_HEIGHT)
  556. X#define TICK_SIZE    50
  557. X#define TEXT_GAP    400
  558. X
  559. X#define TICK_TEXT_GAP    400        /* minimum gap between ticks for log */
  560. X#define TICK_GAP    40
  561. X
  562. X#define RAD        (XSPACE/200)
  563. X
  564. X#define LEGEND_LINE_LENGTH    400
  565. X
  566. X
  567. Xextern double min_fun ();
  568. Xextern double max_fun ();
  569. Xextern double ceil ();
  570. Xextern double pow ();
  571. Xextern double log10 ();
  572. X
  573. X
  574. Xextern graph_st graph[];
  575. Xextern int num_graphs;
  576. Xextern char *graph_label;
  577. Xextern axis_st xaxis;
  578. Xextern axis_st yaxis;
  579. Xextern int horiz_legend;
  580. Xextern int vert_legend;
  581. X
  582. X
  583. X
  584. Xstatic double lastx_clip;    /* buffered coordinate for clip function */
  585. Xstatic double lasty_clip;
  586. X
  587. X
  588. Xdump_graphs ()
  589. X{
  590. X    int i;
  591. X
  592. X    if ( num_graphs < 1 ) {
  593. X    fprintf ( stderr , "No graphs to print\n" );
  594. X    exit ( 0 );
  595. X    }
  596. X
  597. X    if ( xaxis.linear == LOGRITHMIC ) {
  598. X    for ( i = 0; i < num_graphs; i++ )
  599. X        log_tab ( graph[i].table , graph[i].table->next );
  600. X    }
  601. X
  602. X    if ( yaxis.linear == LOGRITHMIC ) {
  603. X    for ( i = 0; i < num_graphs; i++ )
  604. X        log_tab ( graph[i].table->next , graph[i].table );
  605. X    }
  606. X
  607. X    /* plot(3x) routines */
  608. X    openpl ();
  609. X    erase ();
  610. X    space ( 0 , 0 , XSPACE , YSPACE );
  611. X
  612. X    if ( graph_label != NULL ) {
  613. X    move ( XORIGIN + XRANGE / 2 - strlen ( graph_label ) * CHAR_WIDTH / 2 ,
  614. X        YSPACE - CHAR_HEIGHT );
  615. X    label ( graph_label );
  616. X    }
  617. X
  618. X    determine_range ( XAXIS , &xaxis );
  619. X    determine_range ( YAXIS , &yaxis );
  620. X
  621. X    axes ();
  622. X
  623. X    dump_legend ();
  624. X
  625. X    for ( i = 0; i < num_graphs; i++ )
  626. X    draw_graph ( &graph[i] );
  627. X
  628. X    /* plot(3x) */
  629. X    move ( 0 , 0 );
  630. X    closepl ();
  631. X}
  632. X
  633. X
  634. X
  635. X/* discards values <= 0.0 */
  636. X
  637. Xstatic
  638. Xlog_tab ( table , othercol )
  639. Xtable_st *table , *othercol;
  640. X{
  641. X    int i , j;
  642. X    int warn_count;
  643. X
  644. X    warn_count = 0;
  645. X    j = 0;
  646. X    for ( i = 0; i < table->size; i++ ) {
  647. X    if ( table->data[i] > 0.0 ) {
  648. X        othercol->data[j] = othercol->data[i];
  649. X        table->data[j] = log10 ( table->data[i] );
  650. X        j++;
  651. X    }
  652. X    else if ( warn_count++ == 0 )
  653. X        warn ( "negative or zero data to be plotted logrithmically discarded" );
  654. X    }
  655. X    table->size = j;
  656. X    othercol->size = j;
  657. X}
  658. X
  659. X
  660. X
  661. Xstatic
  662. Xdraw_graph ( gptr )
  663. Xgraph_st *gptr;
  664. X{
  665. X    int i , size;
  666. X    int reseti;
  667. X    int basex , basey;
  668. X    double *xdata , *ydata;
  669. X    double lastx , lasty;
  670. X    double newx , newy;
  671. X
  672. X
  673. X    /* necessary for clip function to work safely */
  674. X
  675. X    lasty_clip = -1;
  676. X    lastx_clip = -1;
  677. X
  678. X    /* no data to plot */
  679. X
  680. X    if ( gptr->table->size < 1 )
  681. X    return;
  682. X
  683. X    xdata = gptr->table->data;
  684. X    ydata = gptr->table->next->data;
  685. X    size = gptr->table->size;
  686. X
  687. X    /* draw the line (with clipping) */
  688. X
  689. X    if ( gptr->line_type != NO ) {
  690. X    set_line ( gptr->line_type );
  691. X    lastx = xdata[0];
  692. X    lasty = ydata[0];
  693. X    /* start from 0 (not 1) so a single point will come out as a dot */
  694. X    for ( i = 0; i < size; i++ ) {
  695. X        newx = xdata[i];
  696. X        newy = ydata[i];
  697. X        clip_line ( lastx , lasty , newx , newy );
  698. X        lastx = newx;
  699. X        lasty = newy;
  700. X    }
  701. X    }
  702. X
  703. X    /* Draw any points along the line */
  704. X
  705. X    if ( gptr->point_type != 0 ) {
  706. X    set_line ( SOLID );
  707. X    for ( i = 0; i < size; i++ ) {
  708. X
  709. X        basex = lxscale ( xdata[i] );
  710. X        basey = lyscale ( ydata[i] );
  711. X
  712. X        if ( basex >= XORIGIN  &&  basex <= XORIGIN + XRANGE
  713. X        &&   basey >= YORIGIN  &&  basey <= YORIGIN + YRANGE )
  714. X
  715. X        draw_point ( gptr->point_type , basex , basey );
  716. X    }
  717. X    }
  718. X
  719. X    /* output the graph label */
  720. X
  721. X    set_line ( SOLID );
  722. X    if ( gptr->label != NULL ) {
  723. X    move ( lxscale ( lastx_clip ) , lyscale ( lasty_clip ) );
  724. X    /*move ( lxscale ( xdata[size-1] ) , lyscale ( ydata[size-1] ) );*/
  725. X    label ( gptr->label );
  726. X    }
  727. X}
  728. X
  729. X
  730. X
  731. Xdraw_point ( point_type , basex , basey )
  732. Xint point_type , basex , basey;
  733. X{
  734. X    if ( point_type & MSK_TRIANGLE ) {
  735. X    move ( basex - RAD , basey - RAD * 2 / 3 );
  736. X    cont ( basex + RAD , basey - RAD * 2 / 3 );
  737. X    cont ( basex , basey + RAD * 4 / 3 );
  738. X    cont ( basex - RAD , basey - RAD * 2 / 3 );
  739. X    }
  740. X    
  741. X    if ( point_type & MSK_CROSS ) {
  742. X    move ( basex - RAD , basey - RAD );
  743. X    cont ( basex + RAD , basey + RAD );
  744. X    move ( basex - RAD , basey + RAD );
  745. X    cont ( basex + RAD , basey - RAD );
  746. X    }
  747. X
  748. X    if ( point_type & MSK_PLUS ) {
  749. X    move ( basex - RAD , basey - RAD );
  750. X    cont ( basex + RAD , basey + RAD );
  751. X    move ( basex - RAD , basey + RAD );
  752. X    cont ( basex + RAD , basey - RAD );
  753. X    }
  754. X
  755. X    if ( point_type & MSK_CIRCLE ) {
  756. X    circle ( basex , basey , RAD );
  757. X    }
  758. X    
  759. X    if ( point_type & MSK_SQUARE ) {
  760. X    /* *4/5 is just to make the shapes appear the same size */
  761. X    move ( basex - RAD * 4 / 5 , basey - RAD * 4 / 5 );
  762. X    cont ( basex + RAD * 4 / 5 , basey - RAD * 4 / 5 );
  763. X    cont ( basex + RAD * 4 / 5 , basey + RAD * 4 / 5 );
  764. X    cont ( basex - RAD * 4 / 5 , basey + RAD * 4 / 5 );
  765. X    cont ( basex - RAD * 4 / 5 , basey - RAD * 4 / 5 );
  766. X    }
  767. X}
  768. X
  769. X
  770. Xclip_line ( x1 , y1 , x2 , y2 )
  771. Xdouble x1 , y1 , x2 , y2;
  772. X{
  773. X    double minx , miny , maxx , maxy;
  774. X    int mx1 , my1 , mx2 , my2;
  775. X    double xedge , yedge;
  776. X
  777. X
  778. X    minx = xaxis.range.min;
  779. X    miny = yaxis.range.min;
  780. X    maxx = xaxis.range.max;
  781. X    maxy = yaxis.range.max;
  782. X
  783. X    /* determine which sector the end points are in */
  784. X
  785. X    mx1 = sector ( x1 , minx , maxx );
  786. X    my1 = sector ( y1 , miny , maxy );
  787. X    mx2 = sector ( x2 , minx , maxx );
  788. X    my2 = sector ( y2 , miny , maxy );
  789. X
  790. X    /* points must not be in same sector and off screen */
  791. X
  792. X    if ( mx1 * mx2 != 1  &&  my1 * my2 != 1 ) {
  793. X
  794. X    if ( mx1 != 0 ) {
  795. X
  796. X        /* move point 1 nearer the x-edge of the frame */
  797. X
  798. X        if ( mx1 == 1 )
  799. X        xedge = maxx;
  800. X        else
  801. X        xedge = minx;
  802. X        y1 = y1 + ( y2 - y1 ) * ( xedge - x1 ) / ( x2 - x1 );
  803. X        x1 = xedge;
  804. X
  805. X        /* recompute sector to see if point needs another shift */
  806. X
  807. X        my1 = sector ( y1 , miny , maxy );
  808. X    }
  809. X
  810. X    if ( my1 != 0 ) {
  811. X
  812. X        /* move point 1 nearer the y-edge of the frame */
  813. X
  814. X        if ( my1 == 1 )
  815. X        yedge = maxy;
  816. X        else
  817. X        yedge = miny;
  818. X        x1 = x1 + ( x2 - x1 ) * ( yedge - y1 ) / ( y2 - y1 );
  819. X        y1 = yedge;
  820. X
  821. X    }
  822. X
  823. X    /* ok, now repeat the above for point 2 */
  824. X
  825. X    if ( mx2 != 0 ) {
  826. X
  827. X        /* move point 2 nearer the x-edge of the frame */
  828. X
  829. X        if ( mx2 == 1 )
  830. X        xedge = maxx;
  831. X        else
  832. X        xedge = minx;
  833. X        y2 = y2 + ( y1 - y2 ) * ( xedge - x2 ) / ( x1 - x2 );
  834. X        x2 = xedge;
  835. X
  836. X        /* recompute sector to see if point needs another shift */
  837. X
  838. X        my2 = sector ( y2 , miny , maxy );
  839. X    }
  840. X
  841. X    if ( my2 != 0 ) {
  842. X
  843. X        /* move point 2 nearer the y-edge of the frame */
  844. X
  845. X        if ( my2 == 1 )
  846. X        yedge = maxy;
  847. X        else
  848. X        yedge = miny;
  849. X        x2 = x2 + ( x1 - x2 ) * ( yedge - y2 ) / ( y1 - y2 );
  850. X        y2 = yedge;
  851. X
  852. X    }
  853. X
  854. X    if ( x1 >= minx  &&  x1 <= maxx  &&  x2 >= minx  &&  x2 <= maxx 
  855. X    &&   y1 >= miny  &&  y1 <= maxy  &&  y2 >= miny  &&  y2 <= maxy ) {
  856. X
  857. X        /* use buffered move and cont calls where possible as some */
  858. X        /* plotters do dotted lines better if cont is used for continuous */
  859. X        /* lines. Using separate line() calls means the dotted lines */
  860. X        /* start again per line */
  861. X
  862. X        if ( x1 != lastx_clip  ||  y1 != lasty_clip )
  863. X        move ( xscale ( x1 ) , yscale ( y1 ) );
  864. X        cont ( xscale ( x2 ) , yscale ( y2 ) );
  865. X        lastx_clip = x2;
  866. X        lasty_clip = y2;
  867. X    }
  868. X    }
  869. X}
  870. X
  871. X
  872. Xstatic int
  873. Xsector ( val , min , max )
  874. Xdouble val , min , max;
  875. X{
  876. X    if ( val < min ) return ( -1 );
  877. X    if ( val > max ) return ( 1 );
  878. X    return ( 0 );
  879. X}
  880. X
  881. X
  882. Xstatic
  883. Xset_line ( type )
  884. Xint type;
  885. X{
  886. X    switch ( type ) {
  887. X    case DOTTED : linemod ( "dotted" ); break;
  888. X    case DOTDASHED : linemod ( "dotdashed" ); break;
  889. X    case SHORTDASHED : linemod ( "shortdashed" ); break;
  890. X    case LONGDASHED : linemod ( "longdashed" ); break;
  891. X    default : linemod ( "solid" ); break;
  892. X    }
  893. X}
  894. X
  895. X
  896. Xstatic int
  897. Xxscale ( coord )
  898. Xdouble coord;
  899. X{
  900. X    double xcoord;
  901. X
  902. X    xcoord = ( ( coord - xaxis.range.min )
  903. X    / ( xaxis.range.max - xaxis.range.min ) ) * (double)XRANGE;
  904. X    return ( (int)xcoord + XORIGIN );
  905. X}
  906. X
  907. X
  908. Xstatic int
  909. Xyscale ( coord )
  910. Xdouble coord;
  911. X{
  912. X    double ycoord;
  913. X
  914. X    ycoord = ( ( coord - yaxis.range.min )
  915. X    / ( yaxis.range.max - yaxis.range.min ) ) * (double)YRANGE;
  916. X    return ( (int)ycoord + YORIGIN );
  917. X}
  918. X
  919. X
  920. Xstatic int
  921. Xlxscale ( coord )
  922. Xdouble coord;
  923. X{
  924. X    int xcoord;
  925. X
  926. X    xcoord = xscale ( coord );
  927. X    if ( xcoord < 0 )
  928. X    return ( 0 );
  929. X    if ( xcoord >= XSPACE )
  930. X    return ( XSPACE - 1 );
  931. X    return ( xcoord );
  932. X}
  933. X
  934. X
  935. Xstatic int
  936. Xlyscale ( coord )
  937. Xdouble coord;
  938. X{
  939. X    int ycoord;
  940. X
  941. X    ycoord = yscale ( coord );
  942. X    if ( ycoord < 0 )
  943. X    return ( 0 );
  944. X    if ( ycoord >= YSPACE )
  945. X    return ( YSPACE - 1 );
  946. X    return ( ycoord );
  947. X}
  948. X
  949. X
  950. Xchar *
  951. Xchoose_format ( paxis )
  952. Xstruct axis_st *paxis;
  953. X{
  954. X    double first_log_tick ();
  955. X
  956. X    if ( paxis->linear == LOGRITHMIC ) {
  957. X    paxis->power_10 = floor ( paxis->range.min );
  958. X    paxis->format = "%.0f";
  959. X    /* STILL NOT RIGHT
  960. X    if ( xscale ( first_log_tick ( xaxis.range.min ) ) >= XRANGE + XORIGIN )
  961. X        paxis->format = "%.2f";
  962. X    */
  963. X    }
  964. X    else if ( paxis->auto_tick_size )
  965. X    calc_ticks ( paxis , &paxis->tick_size , &paxis->power_10 );
  966. X
  967. X    if ( paxis->scale == AUTO
  968. X    /* &&  paxis->linear != LOGRITHMIC ???? special scaling ok for log too? */
  969. X    &&  paxis->auto_tick_size ) {
  970. X    if ( paxis->power_10 == 1.0
  971. X    ||   paxis->power_10 == 2.0 ) {
  972. X        paxis->format = "%.0f";
  973. X        paxis->scale = NO;
  974. X    }
  975. X    else if ( paxis->tick_size >= 10.0 )
  976. X        paxis->format = "%.0f";
  977. X    }
  978. X    return ( ( paxis->user_format == NULL )
  979. X    ? paxis->format : paxis->user_format );
  980. X}
  981. X
  982. X
  983. Xstatic
  984. Xaxes ()
  985. X{
  986. X    int xscale ();
  987. X    int yscale ();
  988. X    int lxscale ();
  989. X    int lyscale ();
  990. X    double first_log_tick ();
  991. X    double next_log_tick ();
  992. X    double next_10_tick ();
  993. X
  994. X    int base_x , base_y;
  995. X    int tick_pos;
  996. X    int last_tick_pos;
  997. X    int last_text_pos;
  998. X    int tick_num;
  999. X    int loop_count;
  1000. X    int i;
  1001. X    double tick_value;
  1002. X    double base;
  1003. X    double xaxis_min , yaxis_min;
  1004. X    char buf[500];
  1005. X    char small_buf[2];
  1006. X    char *p , *beg;
  1007. X    int longest , length , num_lines , line_num;
  1008. X    int print_tick;
  1009. X    int best_log_ticks;
  1010. X    char *xformat , *yformat;
  1011. X
  1012. X
  1013. X    xformat = choose_format ( &xaxis );
  1014. X    yformat = choose_format ( &yaxis );
  1015. X
  1016. X    base_x = lxscale ( xaxis.range.min );
  1017. X    base_y = lyscale ( yaxis.range.min );
  1018. X    base = 10.0;
  1019. X    set_line ( SOLID );
  1020. X
  1021. X    if ( xaxis.frame != NO ) {
  1022. X
  1023. X    /* First the x-axis */
  1024. X
  1025. X    /* draw base line */
  1026. X
  1027. X    line ( base_x , base_y , base_x + XRANGE - 1 , base_y );
  1028. X
  1029. X    if ( xaxis.frame == OUTLINE )
  1030. X        line ( base_x , base_y + YRANGE - 1 , base_x + XRANGE - 1 , base_y + YRANGE - 1 );
  1031. X
  1032. X    /* Label the axis */
  1033. X
  1034. X    if ( xaxis.label != NULL ) {
  1035. X        sprintf ( buf ,
  1036. X        ( xaxis.scale != AUTO  ||  xaxis.power_10 == 0.0 )
  1037. X            ? "%s" : "%s x 10^%d" ,
  1038. X        xaxis.label ,
  1039. X        (int)xaxis.power_10 );
  1040. X        move ( base_x + XRANGE / 2 - strlen ( buf ) * CHAR_WIDTH / 2 ,
  1041. X        base_y - TEXT_GAP );
  1042. X        label ( buf );
  1043. X/* fprintf(stderr,"xaxis label '%s'\n",buf);*/
  1044. X    }
  1045. X
  1046. X    /* Put ticks on the axis */
  1047. X
  1048. X/*fprintf(stderr,"power_10 = %f\n",xaxis.power_10);*/
  1049. X    tick_num = 0;
  1050. X    loop_count = 0;
  1051. X    last_tick_pos = 0;
  1052. X    last_text_pos = 0;
  1053. X        
  1054. X    if ( xaxis.linear == LOGRITHMIC ) {
  1055. X        xaxis_min = xaxis.range.min;
  1056. X
  1057. X#if DEBUG
  1058. Xfprintf(stderr,"min = %f\n",xaxis.range.min);
  1059. X#endif
  1060. X
  1061. X        best_log_ticks = xscale ( first_log_tick ( xaxis.range.min ) )
  1062. X        < XRANGE + XORIGIN;
  1063. X        best_log_ticks = 1;    /* override for now */
  1064. X
  1065. X#if DEBUG_LOG
  1066. Xfprintf(stderr,"best = %d, xscale(min) = %d\n",best_log_ticks,xscale(first_log_tick(xaxis.range.min)));
  1067. X#endif
  1068. X
  1069. X    }
  1070. X    else {
  1071. X
  1072. X        /* now, round the value off! If we dont do that, min */
  1073. X        /* values that are strange fractions will cause misleading */
  1074. X        /* values to be printed (%.1f will round fractions to one */
  1075. X        /* decimal place which will be totally wrong for a tick size */
  1076. X        /* of 0.1 */
  1077. X
  1078. X        xaxis_min = ceil ( xaxis.range.min
  1079. X        / ( xaxis.tick_size  * pow ( base , xaxis.power_10 ) ) )
  1080. X        * ( xaxis.tick_size * pow ( base , xaxis.power_10 ) );
  1081. X#if DEBUG
  1082. Xfprintf(stderr,"x.min %f, x.tick_size %f, x.power_10 %f , xaxis_min %f\n",
  1083. Xxaxis.range.min,xaxis.tick_size,xaxis.power_10,xaxis_min);
  1084. X#endif
  1085. X    }
  1086. X
  1087. X    while ( 1 ) {
  1088. X
  1089. X        /* determine value to display next to tick */
  1090. X
  1091. X        if ( xaxis.linear == LOGRITHMIC ) {
  1092. X        if ( best_log_ticks ) {
  1093. X            if ( loop_count == 0 ) {
  1094. X            tick_value = first_log_tick ( xaxis.range.min );
  1095. X#if DEBUG_LOG
  1096. Xfprintf(stderr,"min = %f, max = %f, tick = %f\n",xaxis.range.min,xaxis.range.max,tick_value);
  1097. X#endif
  1098. X            }
  1099. X            else
  1100. X            tick_value = next_log_tick ();
  1101. X        }
  1102. X        else {
  1103. X            tick_value = pow ( 10.0 , xaxis.range.min )
  1104. X            + (double)tick_num
  1105. X            * ( pow( 10.0 , xaxis.range.max )
  1106. X                - pow ( 10.0 , xaxis.range.min ) ) / 5.0;
  1107. X#if DEBUG_LOG
  1108. Xfprintf(stderr,"tick value is %f\n",tick_value);
  1109. X#endif
  1110. X        }
  1111. X        }
  1112. X        else {
  1113. X        tick_value = xaxis_min + (double)tick_num
  1114. X            * xaxis.tick_size * pow ( base , xaxis.power_10 );
  1115. X        }
  1116. X        loop_count++;
  1117. X        
  1118. X        /* determine offset along axis to place tick */
  1119. X
  1120. X        if ( xaxis.linear == LOGRITHMIC )
  1121. X        tick_pos = xscale ( log10 ( tick_value ) );
  1122. X        else
  1123. X        tick_pos = xscale ( tick_value );
  1124. X
  1125. X        /* see if meant to auto scale value */
  1126. X
  1127. X        if ( xaxis.scale == AUTO )
  1128. X        tick_value /= pow ( base , xaxis.power_10 );
  1129. X#if DEBUG_LOG
  1130. Xfprintf(stderr,"scaled tickvalue to %f\n",tick_value);
  1131. X#endif
  1132. X
  1133. X        /* run out of axis? */
  1134. X
  1135. X        if ( tick_pos > XRANGE + XORIGIN )
  1136. X        break;
  1137. X
  1138. X        /* if logrithmic axis, must also check that ticks wont be */
  1139. X        /* too close together */
  1140. X
  1141. X        if ( xaxis.linear == LOGRITHMIC
  1142. X        &&  tick_pos != xscale ( next_10_tick () - 1.0 ) ) {
  1143. X        /* is tick too close to last tick? */
  1144. X        if ( tick_pos < last_tick_pos + TICK_GAP ) {
  1145. X#if DEBUG_LOG
  1146. Xfprintf(stderr,"tick %d (%d) too close to LAST position\n",tick_num,tick_pos);
  1147. X#endif
  1148. X            continue;        /* try next tick */
  1149. X        }
  1150. X        /* is tick too close to next 1,10,100,1000 value? */
  1151. X        if ( tick_pos + TICK_GAP > xscale ( next_10_tick () ) ) {
  1152. X#if DEBUG_LOG
  1153. Xfprintf(stderr,"tick %d (%d) too close to NEXT position\n",tick_num,tick_pos);
  1154. Xfprintf(stderr,"next = %f, xscale(next) = %d\n",next_10_tick (),xscale(next_10_tick()));
  1155. X#endif
  1156. X            continue;        /* try next tick */
  1157. X        }
  1158. X        last_tick_pos = tick_pos;
  1159. X        }
  1160. X
  1161. X        /* draw the actual tick */
  1162. X
  1163. X        if ( xaxis.frame == GRID )
  1164. X        line ( tick_pos , base_y + YRANGE - 1 , tick_pos , base_y );
  1165. X        else
  1166. X        line ( tick_pos , base_y , tick_pos , base_y - TICK_SIZE );
  1167. X
  1168. X        /* print the tick value */
  1169. X
  1170. X        print_tick = 0;
  1171. X        if ( xaxis.linear != LOGRITHMIC )
  1172. X        print_tick = 1;
  1173. X        else if ( tick_pos >= last_text_pos + TICK_TEXT_GAP  ) {
  1174. X        if ( xscale ( 2.0 ) - xscale ( 1.0 ) <= TICK_TEXT_GAP ) {
  1175. X            if ( tick_pos == xscale ( next_10_tick () - 1.0 ) )
  1176. X            print_tick = 1;
  1177. X        }
  1178. X        else {
  1179. X            if ( tick_pos + TICK_TEXT_GAP <= xscale ( next_10_tick () ) )
  1180. X            print_tick = 1;
  1181. X        }
  1182. X        }
  1183. X#if DEBUG|DEBUG_LOG
  1184. Xfprintf(stderr,"tick_pos = %d, 2.0-1.0 = %d, print it %d\n",
  1185. Xtick_pos,xscale(2.0)-xscale(1.0),print_tick);
  1186. X#endif
  1187. X
  1188. X        if ( print_tick ) {
  1189. X        sprintf ( buf , xformat , tick_value );
  1190. X        move ( tick_pos - strlen ( buf ) * CHAR_WIDTH / 2 ,
  1191. X            base_y - ( xaxis.frame == GRID ? 2 : 3 ) * TICK_SIZE );
  1192. X        label ( buf );
  1193. X        last_text_pos = tick_pos;
  1194. X#if DEBUG|DEBUG_LOG
  1195. Xfprintf(stderr,"TICK %d at %d: '%s'\n",tick_num,tick_pos,buf);
  1196. X#endif
  1197. X
  1198. X        }
  1199. X
  1200. X        /* loop until tick position off axis */
  1201. X
  1202. X        tick_num++;
  1203. X        if ( tick_num > 100 )
  1204. X        abort ( "axis tick algorithm failed!!" );
  1205. X    }
  1206. X    }
  1207. X
  1208. X    /* Second, the y-axis */
  1209. X
  1210. X    if ( yaxis.frame != NO ) {
  1211. X
  1212. X    /* draw base line */
  1213. X
  1214. X    line ( base_x , base_y , base_x , base_y + YRANGE - 1 );
  1215. X
  1216. X    if ( yaxis.frame == OUTLINE )
  1217. X        line ( base_x , base_y + YRANGE - 1 , base_x + XRANGE - 1 , base_y + YRANGE - 1 );
  1218. X
  1219. X    /* Label the axis by writing values DOWN the axis */
  1220. X
  1221. X    if ( yaxis.label != NULL ) {
  1222. X        sprintf ( buf ,
  1223. X        ( yaxis.scale != AUTO  ||  yaxis.power_10 == 0.0 )
  1224. X            ? "%s" : "%s x~10^%d" ,
  1225. X        yaxis.label ,
  1226. X        (int)yaxis.power_10 );
  1227. X
  1228. X#ifdef OLD_DOWN_AXIS
  1229. X        for ( i = 0; buf[i] != '\0'; i++ ) {
  1230. X        move ( base_x - TEXT_GAP - 2 * CHAR_WIDTH , base_y + YRANGE / 2
  1231. X            + strlen ( buf ) * CHAR_HEIGHT / 2 - i * CHAR_HEIGHT );
  1232. X        small_buf[0] = buf[i];
  1233. X        small_buf[1] = '\0';
  1234. X        label ( small_buf );
  1235. X        }
  1236. X#else
  1237. X
  1238. X        /* split label into many lines, each line separated by a space. */
  1239. X        /* to allow a space to be force, ~ is mapped to a space at the */
  1240. X        /* last moment. to place the text, each line is centred and */
  1241. X        /* placed so that the longest line touches the edge of the */
  1242. X        /* graph. */
  1243. X
  1244. X        /* first find longest line and number of lines */
  1245. X
  1246. X        longest = 0;
  1247. X        num_lines = 0;
  1248. X        p = buf;
  1249. X        while ( *p != '\0' ) {
  1250. X        num_lines++;
  1251. X        length = 0;
  1252. X        while ( *p != ' '  &&  *p != '\0' ) {
  1253. X            p++;
  1254. X            length++;
  1255. X        }
  1256. X        if ( *p == ' ' )
  1257. X            p++;
  1258. X        if ( length > longest )
  1259. X            longest = length;
  1260. X        }
  1261. X
  1262. X        /* now print yaxis label by replacing blanks with \0 and */
  1263. X        /* ~ with blanks and output each line */
  1264. X
  1265. X        line_num = 0;
  1266. X        p = buf;
  1267. X        while ( *p != '\0' ) {
  1268. X        beg = p;
  1269. X        length = 0;
  1270. X        while ( *p != '\0'  &&  *p != ' ' ) {
  1271. X            if ( *p == '~' )
  1272. X            *p = ' ';
  1273. X            length++;
  1274. X            p++;
  1275. X        }
  1276. X        if ( *p == ' ' )
  1277. X            *p++ = '\0';
  1278. X        move ( ( longest * CHAR_WIDTH/2 ) - ( length * CHAR_WIDTH/2 ) ,
  1279. X            base_y + YRANGE / 2 + num_lines * CHAR_HEIGHT
  1280. X            - line_num * CHAR_HEIGHT * 3 / 2 );
  1281. X        label ( beg );
  1282. X        line_num++;
  1283. X        }
  1284. X
  1285. X#endif
  1286. X    }
  1287. X
  1288. X    /* Put ticks on the axis */
  1289. X
  1290. X    tick_num = 0;
  1291. X    last_tick_pos = 0;
  1292. X    last_text_pos = 0;
  1293. X    loop_count = 0;
  1294. X    
  1295. X    if ( yaxis.linear == LOGRITHMIC ) {
  1296. X        yaxis_min = yaxis.range.min;
  1297. X    }
  1298. X    else {
  1299. X
  1300. X        /* now, round the value off! If we dont do that, min */
  1301. X        /* values that are strange fractions will cause misleading */
  1302. X        /* values to be printed (%.1f will round fractions to one */
  1303. X        /* decimal place which will be totally wrong for a tick size */
  1304. X        /* of 0.1 */
  1305. X
  1306. X        yaxis_min = ceil ( yaxis.range.min
  1307. X        / ( yaxis.tick_size * pow ( base , yaxis.power_10 ) ) )
  1308. X        * ( yaxis.tick_size * pow ( base , yaxis.power_10 ) );
  1309. X    }
  1310. X
  1311. X    while ( 1 ) {
  1312. X
  1313. X        /* determine value to display next to tick */
  1314. X
  1315. X        if ( yaxis.linear == LOGRITHMIC ) {
  1316. X        if ( loop_count == 0 )
  1317. X            tick_value = first_log_tick ( yaxis.range.min );
  1318. X        else
  1319. X            tick_value = next_log_tick ();
  1320. X        }
  1321. X        else {
  1322. X        tick_value = yaxis_min + (double)tick_num
  1323. X            * yaxis.tick_size * pow ( base , yaxis.power_10 );
  1324. X        }
  1325. X        loop_count++;
  1326. X        
  1327. X        /* determine offset along axis to place tick */
  1328. X
  1329. X        if ( yaxis.linear == LOGRITHMIC )
  1330. X        tick_pos = yscale ( log10 ( tick_value ) );
  1331. X        else
  1332. X        tick_pos = yscale ( tick_value );
  1333. X
  1334. X        /* see if meant to auto scale value */
  1335. X
  1336. X        if ( yaxis.scale == AUTO )
  1337. X        tick_value /= pow ( base , yaxis.power_10 );
  1338. X
  1339. X        /* run out of axis? */
  1340. X
  1341. X        if ( tick_pos > YRANGE + YORIGIN )
  1342. X        break;
  1343. X
  1344. X        /* if logrithmic axis, must also check that ticks wont be */
  1345. X        /* too close together */
  1346. X
  1347. X        if ( yaxis.linear == LOGRITHMIC
  1348. X        &&  tick_pos != yscale ( next_10_tick () - 1.0 ) ) {
  1349. X        /* is tick too close to last tick? */
  1350. X        if ( tick_pos < last_tick_pos + TICK_GAP )
  1351. X            continue;        /* try next tick */
  1352. X        /* is tick too close to next 1,10,100,1000 value? */
  1353. X        if ( tick_pos + TICK_GAP > yscale ( next_10_tick () ) )
  1354. X            continue;        /* try next tick */
  1355. X        last_tick_pos = tick_pos;
  1356. X        }
  1357. X
  1358. X        /* draw the actual tick */
  1359. X
  1360. X        if ( yaxis.frame == GRID )
  1361. X        line ( base_x + XRANGE - 1 , tick_pos , base_x , tick_pos );
  1362. X        else
  1363. X        line ( base_x , tick_pos , base_x - TICK_SIZE , tick_pos );
  1364. X
  1365. X        /* print the tick value */
  1366. X
  1367. X        print_tick = 0;
  1368. X        if ( yaxis.linear != LOGRITHMIC )
  1369. X        print_tick = 1;
  1370. X        else if ( tick_pos >= last_text_pos + TICK_TEXT_GAP  ) {
  1371. X        if ( yscale ( 2.0 ) - yscale ( 1.0 ) <= TICK_TEXT_GAP ) {
  1372. X            if ( tick_pos == yscale ( next_10_tick () - 1.0 ) )
  1373. X            print_tick = 1;
  1374. X        }
  1375. X        else {
  1376. X            if ( tick_pos + TICK_TEXT_GAP <= yscale ( next_10_tick () ) )
  1377. X            print_tick = 1;
  1378. X        }
  1379. X        }
  1380. X
  1381. X        if ( print_tick ) {
  1382. X        sprintf ( buf , yformat , tick_value );
  1383. X        move ( base_x - strlen ( buf ) * CHAR_WIDTH
  1384. X            - ( yaxis.frame == GRID ? 1 : 2 ) * TICK_SIZE ,
  1385. X            tick_pos - CHAR_WIDTH / 2 );
  1386. X        label ( buf );
  1387. X        last_text_pos = tick_pos;
  1388. X        }
  1389. X
  1390. X        /* loop until tick position off axis */
  1391. X
  1392. X        tick_num++;
  1393. X        if ( tick_num > 100 )
  1394. X        abort ( "axis tick algorithm failed!!" );
  1395. X    }
  1396. X    }
  1397. X}
  1398. X
  1399. X
  1400. Xstatic
  1401. Xdetermine_range ( which , paxis )
  1402. Xint which;
  1403. Xaxis_st *paxis;
  1404. X{
  1405. X    double floor () , log10 () , pow ();
  1406. X    int i;
  1407. X    double best_min , best_max;
  1408. X    double new_min , new_max;
  1409. X    double round_max;
  1410. X    table_st *table;
  1411. X
  1412. X
  1413. X    /* only automatically calculate range if no range has been specified */
  1414. X    /* (This is indicated by the min value being greater than the max value) */
  1415. X
  1416. X    if ( paxis->range.min >= paxis->range.max ) {
  1417. X
  1418. X    /* scan through all the graphs and determine the largest and */
  1419. X    /* smallest value. */
  1420. X
  1421. X    if ( which == XAXIS )
  1422. X        table = graph[0].table;
  1423. X    else
  1424. X        table = graph[0].table->next;
  1425. X    best_min = min_fun ( table , 0 , table->size - 1 );
  1426. X    best_max = max_fun ( table , 0 , table->size - 1 );
  1427. X    for ( i = 1; i < num_graphs; i++ ) {
  1428. X        if ( which == XAXIS )
  1429. X        table = graph[i].table;
  1430. X        else
  1431. X        table = graph[i].table->next;
  1432. X        new_min = min_fun ( table , 0 , table->size - 1 );
  1433. X        new_max = max_fun ( table , 0 , table->size - 1 );
  1434. X        if ( new_min < best_min )
  1435. X        best_min = new_min;
  1436. X        if ( new_max > best_max )
  1437. X        best_max = new_max;
  1438. X    }
  1439. X
  1440. X    /* check for zero height graph */
  1441. X
  1442. X    if ( best_min == best_max ) {
  1443. X        
  1444. X        /* give the graph some height */
  1445. X
  1446. X        if ( best_min == 0.0 ) {
  1447. X        best_min = -1.0;
  1448. X        best_max = 1.0;
  1449. X        }
  1450. X        else if ( best_min > 0.0 ) {
  1451. X        if ( paxis->linear == LOGRITHMIC )
  1452. X            best_min = best_min / 2.0;
  1453. X        else
  1454. X            best_min = 0;
  1455. X        best_max = 2.0 * best_max;
  1456. X        }
  1457. X        else {
  1458. X        best_min = best_min * 0.9;
  1459. X        best_max = best_max * 1.1;
  1460. X        }
  1461. X    }
  1462. X
  1463. X    /* make min a nice round value (eg: 4-1000 => 0-1000) */
  1464. X
  1465. X    if ( best_max > 0.0 ) {
  1466. X        round_max = pow ( (double)10.0 , floor ( log10 ( best_max / 3.0 ) ) );
  1467. X        if ( round_max > 0.0 )
  1468. X        best_min = floor ( best_min / round_max ) * round_max * 0.999;
  1469. X    }
  1470. X    /*
  1471. X    if ( paxis->linear != LOGRITHMIC ) {
  1472. X        if ( best_max > 0.0 ) {
  1473. X        round_max = pow ( (double)10.0 , floor ( log10 ( best_max ) ) );
  1474. X        best_min = floor ( best_min / round_max ) * round_max;
  1475. X        }
  1476. X    }
  1477. X    else {
  1478. X        if ( best_max > 1.0 ) {
  1479. X        round_max = pow ( (double)10.0 , floor ( log10 ( best_max ) ) );
  1480. X        best_min = floor ( best_min / round_max ) * round_max;
  1481. X        }
  1482. X    }
  1483. X    */
  1484. X#if 0
  1485. X    /* to stop 0->infinity graphs from hanging the program */
  1486. X    if ( paxis->linear == LOGRITHMIC ) {
  1487. X        if ( best_min < best_max / 5.0 )
  1488. X        best_min = best_max / 5.0;
  1489. X            /* remember, this is 10^5.0 */
  1490. X    }
  1491. X#endif
  1492. X    paxis->range.min = best_min;
  1493. X    paxis->range.max = best_max;
  1494. X    }
  1495. X    else if ( paxis->linear == LOGRITHMIC ) {
  1496. X
  1497. X    /* convert values to actual values */
  1498. X
  1499. X    if ( paxis->range.min <= 0.0 )
  1500. X        abort ( "Minimum value for axis on log graph is <= 0" );
  1501. X    paxis->range.min = log10 ( paxis->range.min );
  1502. X    paxis->range.max = log10 ( paxis->range.max );
  1503. X    }
  1504. X}
  1505. X
  1506. X
  1507. X
  1508. Xstatic
  1509. Xcalc_ticks ( paxis , tick , power )
  1510. Xaxis_st *paxis;
  1511. Xdouble *tick , *power;
  1512. X{
  1513. X    double log10 ();
  1514. X    double base , delta;
  1515. X    int power_of_10;
  1516. X    double tick_size;
  1517. X
  1518. X    base = 10.0;
  1519. X    delta = paxis->range.max - paxis->range.min;
  1520. X    power_of_10 = (int) floor ( log10 ( delta ) );
  1521. X    tick_size = delta / pow ( base , (double)(power_of_10+1) );
  1522. X    if ( tick_size <= 0.5 ) {
  1523. X    tick_size = ceil ( (double)( tick_size * 10.0 ) ) / (double)10.0;
  1524. X    }
  1525. X    else {
  1526. X    tick_size = 0.1;
  1527. X    power_of_10++;
  1528. X    }
  1529. X
  1530. X    /* round tick size off to x10 ^3,6,9,12,.... which people understand */
  1531. X    switch ( power_of_10 % 3 ) {
  1532. X    case 0 :        /* already mult of 3 */
  1533. X    break;
  1534. X    case 1 :        /* its just too high (by one) */
  1535. X    tick_size *= 10.0;
  1536. X    power_of_10--;
  1537. X    break;
  1538. X    case 2 :        /* its just too low (by one) */
  1539. X    /*
  1540. X    tick_size /= 10.0;
  1541. X    power_of_10++;
  1542. X    */
  1543. X    tick_size *= 100.0;
  1544. X    power_of_10 -= 2;
  1545. X    break;
  1546. X    }
  1547. X
  1548. X    *tick = tick_size;
  1549. X    *power = (double)power_of_10;
  1550. X}
  1551. X
  1552. X
  1553. X
  1554. Xstatic int lt_value;
  1555. Xstatic int lt_power;
  1556. X
  1557. X
  1558. Xstatic double
  1559. Xfirst_log_tick ( value )
  1560. Xdouble value;
  1561. X{
  1562. X    double actual;
  1563. X    double ret_val;
  1564. X
  1565. X    actual = pow ( (double)10.0 , value );
  1566. X    lt_power = (int) floor ( log10 ( actual ) );
  1567. X    lt_value = (int) ceil ( actual / pow ( (double)10.0 , (double)lt_power ) );
  1568. X    while ( lt_value >= 10 ) {
  1569. X    lt_value /= 10;
  1570. X    lt_power++;
  1571. X    }
  1572. X    ret_val = (double)lt_value * pow ( (double)10.0 , (double)lt_power );
  1573. X/*fprintf(stderr,"first_log_tick: lt_power = %d, lt_value = %d, ret_val = %f\n",lt_power,lt_value,ret_val);*/
  1574. X    return ( ret_val );
  1575. X}
  1576. X
  1577. X
  1578. Xstatic double
  1579. Xnext_log_tick ()
  1580. X{
  1581. X    lt_value++;
  1582. X    while ( lt_value >= 10 ) {
  1583. X    lt_value /= 10;
  1584. X    lt_power++;
  1585. X    }
  1586. X    return ( (double)lt_value * pow ( (double)10.0 , (double)lt_power ) );
  1587. X}
  1588. X
  1589. X
  1590. Xstatic double
  1591. Xnext_10_tick ()
  1592. X{
  1593. X    return ( (double)( lt_power + 1 ) );
  1594. X}
  1595. X
  1596. X
  1597. Xstatic
  1598. Xdump_legend ()
  1599. X{
  1600. X    int i;
  1601. X    int num_lines;
  1602. X    int longest;
  1603. X    int basex , basey;
  1604. X
  1605. X
  1606. X    /* first determine how much is going to be output, and what is the */
  1607. X    /* longest string that is to be output */
  1608. X
  1609. X    num_lines = 0;
  1610. X    longest = 0;
  1611. X    for ( i = 0; i < num_graphs; i++ ) {
  1612. X    if ( graph[i].legend != NULL ) {
  1613. X        num_lines++;
  1614. X        if ( strlen ( graph[i].legend ) > longest )
  1615. X        longest = strlen ( graph[i].legend );
  1616. X    }
  1617. X    }
  1618. X
  1619. X    /* ok, now we want to work out where to start outputing the legend  */
  1620. X
  1621. X    switch ( horiz_legend ) {
  1622. X
  1623. X    case LEFT :
  1624. X    basex = XORIGIN + CHAR_WIDTH * 3;
  1625. X    break;
  1626. X
  1627. X    case CENTER :
  1628. X    basex = XORIGIN + XRANGE / 2 - ( longest * CHAR_WIDTH - LEGEND_LINE_LENGTH ) / 2;
  1629. X    break;
  1630. X    
  1631. X    case RIGHT :
  1632. X    basex = XORIGIN + XRANGE - longest * CHAR_WIDTH - 3 * CHAR_WIDTH - LEGEND_LINE_LENGTH - CHAR_WIDTH;
  1633. X    break;
  1634. X    }
  1635. X
  1636. X    switch ( vert_legend ) {
  1637. X
  1638. X    case TOP :
  1639. X    basey = YORIGIN + YRANGE - CHAR_HEIGHT * 2;
  1640. X    break;
  1641. X
  1642. X    case MIDDLE :
  1643. X    basey = YORIGIN + YRANGE / 2 + num_lines * CHAR_HEIGHT / 2;
  1644. X    break;
  1645. X
  1646. X    case BOTTOM :
  1647. X    basey = YORIGIN + CHAR_HEIGHT * 1 + num_lines * CHAR_HEIGHT;
  1648. X    break;
  1649. X    }
  1650. X
  1651. X    /* ok, now loop through and acutally output the legend! */
  1652. X
  1653. X    for ( i = 0; i < num_graphs; i++ ) {
  1654. X    if ( graph[i].legend != NULL ) {
  1655. X        if ( graph[i].line_type != NO ) {
  1656. X        set_line ( graph[i].line_type );
  1657. X        line ( basex , basey , basex + LEGEND_LINE_LENGTH , basey );
  1658. X        }
  1659. X        set_line ( SOLID );
  1660. X        draw_point ( graph[i].point_type , basex + LEGEND_LINE_LENGTH / 2 , basey );
  1661. X        move ( basex + LEGEND_LINE_LENGTH + CHAR_WIDTH , basey - CHAR_HEIGHT / 3 );
  1662. X        label ( graph[i].legend );
  1663. X        basey -= CHAR_HEIGHT;
  1664. X    }
  1665. X    }
  1666. X}
  1667. SHAR_EOF
  1668. if test 27046 -ne "`wc -c < 'dumpgrph.c'`"
  1669. then
  1670.     echo shar: error transmitting "'dumpgrph.c'" '(should have been 27046 characters)'
  1671. fi
  1672. fi
  1673. if test -f 'eval.c'
  1674. then
  1675.     echo shar: will not over-write existing file "'eval.c'"
  1676. else
  1677. echo extracting "'eval.c'"
  1678. sed 's/^X//' >eval.c <<'SHAR_EOF'
  1679. X/*
  1680. X * Copyright (C) 1986   Alan Kent
  1681. X *
  1682. X * Permission is granted to freely distribute part or
  1683. X * all of this code as long as it is not for profit
  1684. X * and this message is retained in the code.
  1685. X *
  1686. X * No resposibility is taken for any damage or incorect
  1687. X * results this program generates.
  1688. X * 
  1689. X */
  1690. X
  1691. X
  1692. X#include <stdio.h>
  1693. X#include <math.h>
  1694. X#include "graph.h"
  1695. X#include "y.tab.h"
  1696. X
  1697. X
  1698. Xextern double var_lookup ();
  1699. Xextern double call_var_fun ();
  1700. X
  1701. X
  1702. X/* evaluate an expression tree */
  1703. X
  1704. Xdouble
  1705. Xeval ( table , row , expr )
  1706. Xregister table_st *table;
  1707. Xregister int row;
  1708. Xregister attr_st *expr;
  1709. X{
  1710. X    register table_st *tp;
  1711. X    register int i;
  1712. X    int intval;
  1713. X    double value;
  1714. X    double val1 , val2;
  1715. X
  1716. X
  1717. X    if ( expr == NULL )
  1718. X    return ( 0.0 );
  1719. X
  1720. X    switch ( expr->node_type ) {
  1721. X
  1722. X    case PLUS :
  1723. X    value = eval ( table , row , expr->left )
  1724. X    + eval ( table , row , expr->right );
  1725. X    break;
  1726. X
  1727. X    case MINUS :
  1728. X    value = ( eval ( table , row , expr->left )
  1729. X    - eval ( table , row , expr->right ) );
  1730. X    break;
  1731. X
  1732. X    case MULTIPLY :
  1733. X    value = ( eval ( table , row , expr->left )
  1734. X    * eval ( table , row , expr->right ) );
  1735. X    break;
  1736. X
  1737. X    case DIVIDE :
  1738. X    val1 = eval ( table , row , expr->left );
  1739. X    val2 =  eval ( table , row , expr->right );
  1740. X    if ( val2 == 0.0 ) {
  1741. X        value = HUGE;
  1742. X        warn ( "division by zero error" );
  1743. X    }
  1744. X    else
  1745. X        value = val1 / val2;
  1746. X    break;
  1747. X
  1748. X    case MODULUS :
  1749. X    val1 = eval ( table , row , expr->left );
  1750. X    val2 = eval ( table , row , expr->right );
  1751. X    if ( val2 == 0.0 ) {
  1752. X        value = 0.0;
  1753. X        warn ( "modulus by zero error" );
  1754. X    }
  1755. X    else {
  1756. X        while ( val1 > val2 )    /* % does not work with float's */
  1757. X        val1 -= val2;
  1758. X        while ( val1 < 0.0 )
  1759. X        val1 += val2;
  1760. X        value = val1;
  1761. X    }
  1762. X    break;
  1763. X
  1764. X    case LE :
  1765. X    value = ( eval ( table , row , expr->left )
  1766. X    <= eval ( table , row , expr->right ) );
  1767. X    break;
  1768. X
  1769. X    case LT :
  1770. X    value = ( eval ( table , row , expr->left )
  1771. X    < eval ( table , row , expr->right ) );
  1772. X    break;
  1773. X
  1774. X    case GE :
  1775. X    value = ( eval ( table , row , expr->left )
  1776. X    >= eval ( table , row , expr->right ) );
  1777. X    break;
  1778. X
  1779. X    case GT :
  1780. X    value = ( eval ( table , row , expr->left )
  1781. X    > eval ( table , row , expr->right ) );
  1782. X    break;
  1783. X
  1784. X    case EQ :
  1785. X    value = ( eval ( table , row , expr->left )
  1786. X    == eval ( table , row , expr->right ) );
  1787. X    break;
  1788. X
  1789. X    case NE :
  1790. X    value = ( eval ( table , row , expr->left )
  1791. X    != eval ( table , row , expr->right ) );
  1792. X    break;
  1793. X
  1794. X    case QUEST :
  1795. X    value = ( eval ( table , row , expr->left ) != 0.0 )
  1796. X        ? eval ( table , row , expr->right->left )
  1797. X        : eval ( table , row , expr->right->right );
  1798. X    break;
  1799. X
  1800. X    case AND :
  1801. X    value = ( eval ( table , row , expr->left )
  1802. X    && eval ( table , row , expr->right ) );
  1803. X    break;
  1804. X
  1805. X    case OR :
  1806. X    value = ( eval ( table , row , expr->left )
  1807. X    || eval ( table , row , expr->right ) );
  1808. X    break;
  1809. X
  1810. X    case NOT :
  1811. X    value = ( eval ( table , row , expr->left ) == 0.0 );
  1812. X    break;
  1813. X
  1814. X    case NEG :
  1815. X    value = ( - eval ( table , row , expr->left ) );
  1816. X    break;
  1817. X
  1818. X    case FVAR_IDENT :
  1819. X    value = call_var_fun ( expr->ident , expr->parm_list , table , row );
  1820. X    break;
  1821. X
  1822. X    case VAR_IDENT :
  1823. X    value = var_lookup ( expr->ident );
  1824. X    break;
  1825. X
  1826. X    case NUMBER :
  1827. X    value = ( expr->value );
  1828. X    break;
  1829. X
  1830. X    case ATTR :
  1831. X    intval = (int) eval ( table , row , expr->left );
  1832. X    if ( intval == 0 )
  1833. X        value = row + 1.0;
  1834. X    else {
  1835. X        for ( i = 1 , tp = table; tp != NULL  &&  i < intval; i++ , tp = tp->next )
  1836. X        ;
  1837. X        if ( tp == NULL )
  1838. X        abort ( "Illegal attribute number selected from table" );
  1839. X        if ( row >= tp->size )
  1840. X        abort ( "Internal error - accessing past end of array in eval()" );
  1841. X        value = ( tp->data[row] );
  1842. X    }
  1843. X    break;
  1844. X
  1845. X    default :
  1846. X    value = 0.0;
  1847. X    abort ( "Unknown operator in eval() = %d" , expr->node_type );
  1848. X    }
  1849. X    return ( value );
  1850. X}
  1851. X
  1852. SHAR_EOF
  1853. if test 3653 -ne "`wc -c < 'eval.c'`"
  1854. then
  1855.     echo shar: error transmitting "'eval.c'" '(should have been 3653 characters)'
  1856. fi
  1857. fi
  1858. if test -f 'evaltab.c'
  1859. then
  1860.     echo shar: will not over-write existing file "'evaltab.c'"
  1861. else
  1862. echo extracting "'evaltab.c'"
  1863. sed 's/^X//' >evaltab.c <<'SHAR_EOF'
  1864. X/*
  1865. X * Copyright (C) 1986   Alan Kent
  1866. X *
  1867. X * Permission is granted to freely distribute part or
  1868. X * all of this code as long as it is not for profit
  1869. X * and this message is retained in the code.
  1870. X *
  1871. X * No resposibility is taken for any damage or incorect
  1872. X * results this program generates.
  1873. X * 
  1874. X */
  1875. X
  1876. X
  1877. X#include <stdio.h>
  1878. X#include "graph.h"
  1879. X#include "y.tab.h"
  1880. X
  1881. X
  1882. Xextern table_st *append_tables ();
  1883. Xextern table_st *adjacent ();
  1884. Xextern table_st *project ();
  1885. Xextern table_st *select ();
  1886. Xextern table_st *sort ();
  1887. Xextern table_st *join ();
  1888. Xextern table_st *tab_lookup ();
  1889. Xextern table_st *group ();
  1890. Xextern table_st *cumulate ();
  1891. Xextern table_st *generate ();
  1892. Xextern table_st *call_tab_fun ();
  1893. Xextern table_st *new_table ();
  1894. Xextern table_st *copy_of_table ();
  1895. Xextern double eval ();
  1896. X
  1897. X
  1898. Xtable_st *
  1899. Xeval_tab ( expr )
  1900. Xtnode_st *expr;
  1901. X{
  1902. X    trow_st *trp;
  1903. X    tcol_st *tcp;
  1904. X    int num_rows , num_cols , tmp_cols;
  1905. X    table_st *newtab , *tp;
  1906. X    int row;
  1907. X
  1908. X
  1909. X    switch ( expr->operator ) {
  1910. X
  1911. X    case TABLE :
  1912. X    num_rows = 0;
  1913. X    num_cols = 0;
  1914. X    for ( trp = expr->const_table; trp != NULL; trp = trp->next ) {
  1915. X        tmp_cols = 0;
  1916. X        for ( tcp = trp->cols; tcp != NULL; tcp = tcp->next ) {
  1917. X        tmp_cols++;
  1918. X        }
  1919. X        if ( num_rows == 0 )
  1920. X        num_cols = tmp_cols;
  1921. X        else
  1922. X        if ( num_cols != tmp_cols )
  1923. X            abort ( "constant table has rows with different number of columns" );
  1924. X        num_rows++;
  1925. X    }
  1926. X    newtab = new_table ( num_cols , num_rows );
  1927. X    row = 0;
  1928. X    for ( trp = expr->const_table; trp != NULL; trp = trp->next ) {
  1929. X        for ( tcp = trp->cols, tp = newtab; tcp != NULL; tcp = tcp->next, tp = tp->next ) {
  1930. X        tp->data[ row ] = eval ( NULL , 0 , tcp->expr );
  1931. X        }
  1932. X        row++;
  1933. X    }
  1934. X    return ( newtab );
  1935. X    break;
  1936. X
  1937. X    case TAB_CONST :
  1938. X    return ( copy_of_table ( expr->table ) );
  1939. X    
  1940. X    case FTAB_IDENT :
  1941. X    return ( call_tab_fun ( expr->ident , expr->parm_list , NULL , 0 ) );
  1942. X
  1943. X    case APPEND :
  1944. X    return ( append_tables ( eval_tab ( expr->left ) ,
  1945. X        eval_tab ( expr->right ) ) );
  1946. X    
  1947. X    case ADJACENT :
  1948. X    return ( adjacent ( eval_tab ( expr->left ) ,
  1949. X        eval_tab ( expr->right ) ) );
  1950. X    
  1951. X    case PROJECT :
  1952. X    return ( project ( eval_tab ( expr->left ) , expr->expr_list ) );
  1953. X
  1954. X    case WHERE :
  1955. X    return ( select ( eval_tab ( expr->left ) , expr->expr ) );
  1956. X
  1957. X    case SORT :
  1958. X    return ( sort ( eval_tab ( expr->left ) , (int)eval ( NULL , 0 , expr->expr ) ) );
  1959. X
  1960. X    case JOIN :
  1961. X    return ( join ( eval_tab ( expr->left ) , eval_tab ( expr->right ) ,
  1962. X        (int)eval ( NULL , 0 , expr->expr->left ) ,
  1963. X        (int)eval ( NULL , 0 , expr->expr->right ) ) );
  1964. X
  1965. X    case CUMULATE :
  1966. X    return ( cumulate ( eval_tab ( expr->left ) , (int)eval ( NULL , 0 , expr->expr ) ) );
  1967. X
  1968. X    case GENERATE :
  1969. X    return ( generate ( expr->range , expr->interval ) );
  1970. X
  1971. X    case TAB_IDENT :
  1972. X    return ( tab_lookup ( expr->ident ) );
  1973. X
  1974. X    case GROUP :
  1975. X    return ( group ( eval_tab ( expr->left ) , expr->range , expr->interval , expr->ident ) );
  1976. X
  1977. X    default :
  1978. X    abort ( "unknown operator in eval_tab: %d" , expr->operator );
  1979. X
  1980. X    }
  1981. X    return ( NULL );
  1982. X}
  1983. SHAR_EOF
  1984. if test 2981 -ne "`wc -c < 'evaltab.c'`"
  1985. then
  1986.     echo shar: error transmitting "'evaltab.c'" '(should have been 2981 characters)'
  1987. fi
  1988. fi
  1989. if test -f 'freetab.c'
  1990. then
  1991.     echo shar: will not over-write existing file "'freetab.c'"
  1992. else
  1993. echo extracting "'freetab.c'"
  1994. sed 's/^X//' >freetab.c <<'SHAR_EOF'
  1995. X/*
  1996. X * Copyright (C) 1986   Alan Kent
  1997. X *
  1998. X * Permission is granted to freely distribute part or
  1999. X * all of this code as long as it is not for profit
  2000. X * and this message is retained in the code.
  2001. X *
  2002. X * No resposibility is taken for any damage or incorect
  2003. X * results this program generates.
  2004. X * 
  2005. X */
  2006. X
  2007. X
  2008. X
  2009. X#include <stdio.h>
  2010. X#include "graph.h"
  2011. X
  2012. X
  2013. Xfree_table ( table )
  2014. Xtable_st *table;
  2015. X{
  2016. X    table_st *p;
  2017. X
  2018. X    while ( table != NULL ) {
  2019. X    p = table->next;
  2020. X    release ( table->data );
  2021. X    release ( table );
  2022. X    table = p;
  2023. X    }
  2024. X}
  2025. X
  2026. SHAR_EOF
  2027. if test 509 -ne "`wc -c < 'freetab.c'`"
  2028. then
  2029.     echo shar: error transmitting "'freetab.c'" '(should have been 509 characters)'
  2030. fi
  2031. fi
  2032. if test -f 'fundeclr.c'
  2033. then
  2034.     echo shar: will not over-write existing file "'fundeclr.c'"
  2035. else
  2036. echo extracting "'fundeclr.c'"
  2037. sed 's/^X//' >fundeclr.c <<'SHAR_EOF'
  2038. X/*
  2039. X * Copyright (C) 1986   Alan Kent
  2040. X *
  2041. X * Permission is granted to freely distribute part or
  2042. X * all of this code as long as it is not for profit
  2043. X * and this message is retained in the code.
  2044. X *
  2045. X * No resposibility is taken for any damage or incorect
  2046. X * results this program generates.
  2047. X * 
  2048. X */
  2049. X
  2050. X
  2051. X#include <stdio.h>
  2052. X#include "graph.h"
  2053. X#include "y.tab.h"
  2054. X#include "math.h"
  2055. X
  2056. X
  2057. Xextern double eval ();
  2058. Xextern table_st *eval_tab ();
  2059. Xextern double min_fun ();
  2060. Xextern double max_fun ();
  2061. Xextern double sum_fun ();
  2062. Xextern double count_fun ();
  2063. Xextern double average_fun ();
  2064. X
  2065. X
  2066. X#define MIN_FUN        ((attr_st *)2)
  2067. X#define MAX_FUN        ((attr_st *)3)
  2068. X#define SUM_FUN        ((attr_st *)4)
  2069. X#define COUNT_FUN    ((attr_st *)5)
  2070. X#define AVERAGE_FUN    ((attr_st *)6)
  2071. X#define LOG_FUN        ((attr_st *)7)
  2072. X#define LN_FUN        ((attr_st *)8)
  2073. X#define EXP_FUN        ((attr_st *)9)
  2074. X#define POWER_FUN    ((attr_st *)10)
  2075. X#define SQRT_FUN    ((attr_st *)11)
  2076. X#define FLOOR_FUN    ((attr_st *)12)
  2077. X#define CEIL_FUN    ((attr_st *)13)
  2078. X#define ABS_FUN        ((attr_st *)14)
  2079. X#define SIN_FUN        ((attr_st *)15)
  2080. X#define COS_FUN        ((attr_st *)16)
  2081. X#define ASIN_FUN    ((attr_st *)17)
  2082. X#define ACOS_FUN    ((attr_st *)18)
  2083. X#define ATAN_FUN    ((attr_st *)19)
  2084. X#define ATAN2_FUN    ((attr_st *)20)
  2085. X#define SINH_FUN    ((attr_st *)21)
  2086. X#define COSH_FUN    ((attr_st *)22)
  2087. X#define TANH_FUN    ((attr_st *)23)
  2088. X#define HYPOT_FUN    ((attr_st *)24)
  2089. X#define J0_FUN        ((attr_st *)26)
  2090. X#define J1_FUN        ((attr_st *)27)
  2091. X#define JN_FUN        ((attr_st *)28)
  2092. X#define Y0_FUN        ((attr_st *)29)
  2093. X#define Y1_FUN        ((attr_st *)30)
  2094. X#define YN_FUN        ((attr_st *)31)
  2095. X
  2096. X
  2097. X#define MAX_DEC        50
  2098. X
  2099. X
  2100. Xstatic struct declare_st {
  2101. X    char *name;
  2102. X    parm_st *parm_list;
  2103. X    attr_st *expr;
  2104. X    tnode_st *tab_expr;
  2105. X} dec [ MAX_DEC ];
  2106. X
  2107. Xstatic int num_dec;
  2108. X
  2109. X
  2110. X
  2111. Xpdef_fun ()
  2112. X{
  2113. X    static parm_st ptab;
  2114. X    static parm_st pexpr1 , pexpr2;
  2115. X
  2116. X    ptab.parm_type = TABLE;
  2117. X    ptab.ident = "";
  2118. X    ptab.next = NULL;
  2119. X
  2120. X    pexpr1.parm_type = VALUE;
  2121. X    pexpr1.ident = "";
  2122. X    pexpr1.next = NULL;
  2123. X
  2124. X    pexpr2.parm_type = VALUE;
  2125. X    pexpr2.ident = "";
  2126. X    pexpr2.next = &pexpr1;
  2127. X
  2128. X    fun_declare ( "min" , &ptab , MIN_FUN , NULL );
  2129. X    fun_declare ( "max" , &ptab , MAX_FUN , NULL );
  2130. X    fun_declare ( "sum" , &ptab , SUM_FUN , NULL );
  2131. X    fun_declare ( "count" , &ptab , COUNT_FUN , NULL );
  2132. X    fun_declare ( "average" , &ptab , AVERAGE_FUN , NULL );
  2133. X
  2134. X    fun_declare ( "sqrt" , &pexpr1 , SQRT_FUN , NULL );
  2135. X    fun_declare ( "log" , &pexpr1 , LOG_FUN , NULL );
  2136. X    fun_declare ( "ln" , &pexpr1 , LN_FUN , NULL );
  2137. X    fun_declare ( "exp" , &pexpr1 , EXP_FUN , NULL );
  2138. X    fun_declare ( "pow" , &pexpr2 , POWER_FUN , NULL );
  2139. X    fun_declare ( "floor" , &pexpr1 , FLOOR_FUN , NULL );
  2140. X    fun_declare ( "ceil" , &pexpr1 , CEIL_FUN , NULL );
  2141. X    fun_declare ( "abs" , &pexpr1 , ABS_FUN , NULL );
  2142. X
  2143. X    fun_declare ( "sin" , &pexpr1 , SIN_FUN , NULL );
  2144. X    fun_declare ( "cos" , &pexpr1 , COS_FUN , NULL );
  2145. X    fun_declare ( "asin" , &pexpr1 , ASIN_FUN , NULL );
  2146. X    fun_declare ( "acos" , &pexpr1 , ACOS_FUN , NULL );
  2147. X    fun_declare ( "atan" , &pexpr1 , ATAN_FUN , NULL );
  2148. X    fun_declare ( "atan2" , &pexpr2 , ATAN2_FUN , NULL );
  2149. X    fun_declare ( "sinh" , &pexpr1 , SINH_FUN , NULL );
  2150. X    fun_declare ( "cosh" , &pexpr1 , COSH_FUN , NULL );
  2151. X    fun_declare ( "tanh" , &pexpr1 , TANH_FUN , NULL );
  2152. X
  2153. X    fun_declare ( "hypot" , &pexpr2 , HYPOT_FUN , NULL );
  2154. X
  2155. X    fun_declare ( "j0" , &pexpr1 , J0_FUN , NULL );
  2156. X    fun_declare ( "j1" , &pexpr1 , J1_FUN , NULL );
  2157. X    fun_declare ( "jn" , &pexpr2 , JN_FUN , NULL );
  2158. X    fun_declare ( "y0" , &pexpr1 , Y0_FUN , NULL );
  2159. X    fun_declare ( "y1" , &pexpr1 , Y1_FUN , NULL );
  2160. X    fun_declare ( "yn" , &pexpr2 , YN_FUN , NULL );
  2161. X}
  2162. X
  2163. X
  2164. Xfun_declare ( name , parm_list , expr , tab_expr )
  2165. Xchar *name;
  2166. Xparm_st *parm_list;
  2167. Xattr_st *expr;
  2168. Xtnode_st *tab_expr;
  2169. X{
  2170. X    int i;
  2171. X
  2172. X    for ( i = 0; i < num_dec; i++ ) {
  2173. X    if ( strcmp ( name , dec[i].name ) == 0 ) {
  2174. X        abort ( "cannot redeclare functions: '%s'" , name );
  2175. X        return;
  2176. X    }
  2177. X    }
  2178. X    if ( num_dec >= MAX_DEC )
  2179. X    abort ( "Internal array overflow - too many functions declared" );
  2180. X    dec[num_dec].name = name;
  2181. X    dec[num_dec].parm_list = parm_list;
  2182. X    dec[num_dec].expr = expr;
  2183. X    dec[num_dec].tab_expr = tab_expr;
  2184. X    num_dec++;
  2185. X}
  2186. X
  2187. X
  2188. Xdouble
  2189. Xcall_var_fun ( name , parm_list , table , row )
  2190. Xchar *name;
  2191. Xparm_st *parm_list;
  2192. Xtable_st *table;
  2193. Xint row;
  2194. X{
  2195. X    int i;
  2196. X    double value;
  2197. X    parm_st *p1 , *p2;
  2198. X#define MAX_TAB 3
  2199. X#define MAX_VAR 3
  2200. X    table_st *tab_parm[ MAX_TAB ];
  2201. X    double var_parm[ MAX_VAR ];
  2202. X    int tab_num , var_num;
  2203. X
  2204. X    for ( i = 0; i < num_dec; i++ ) {
  2205. X    if ( strcmp ( dec[i].name , name ) == 0 ) {
  2206. X
  2207. X        if ( dec[i].expr == NULL )
  2208. X        abort ( "value function with no expression found" );
  2209. X
  2210. X        p1 = parm_list;
  2211. X        p2 = dec[i].parm_list;
  2212. X        var_num = 0;
  2213. X        tab_num = 0;
  2214. X        while ( p1 != NULL  &&  p2 != NULL ) {
  2215. X
  2216. X        if ( p1->parm_type != p2->parm_type )
  2217. X            abort ( "type mismatch for parameter to function '%s'" , name );
  2218. X
  2219. X        if ( p1->parm_type == TABLE ) {
  2220. X            tab_parm[ tab_num ] = eval_tab ( p1->tab_expr );
  2221. X            tab_declare ( p2->ident , tab_parm[ tab_num ] );
  2222. X            if ( tab_num + 1 < MAX_TAB )
  2223. X            tab_num++;
  2224. X        }
  2225. X        else {
  2226. X            var_parm[ var_num ] = eval ( table , row , p1->expr );
  2227. X            var_declare ( p2->ident , var_parm[ var_num ] );
  2228. X            if ( var_num + 1 < MAX_VAR )
  2229. X            var_num++;
  2230. X        }
  2231. X        p1 = p1->next;
  2232. X        p2 = p2->next;
  2233. X        }
  2234. X        if ( p1 != NULL  ||  p2 != NULL )
  2235. X        abort ( "illegal parameter list for function '%s'" , name );
  2236. X
  2237. X        switch ( dec[i].expr ) {
  2238. X
  2239. X        case MIN_FUN :
  2240. X        value = min_fun ( tab_parm[0] , 0 , tab_parm[0]->size );
  2241. X        break;
  2242. X
  2243. X        case MAX_FUN :
  2244. X        value = max_fun ( tab_parm[0] , 0 , tab_parm[0]->size );
  2245. X        break;
  2246. X
  2247. X        case SUM_FUN :
  2248. X        value = sum_fun ( tab_parm[0] , 0 , tab_parm[0]->size );
  2249. X        break;
  2250. X
  2251. X        case COUNT_FUN :
  2252. X        value = count_fun ( tab_parm[0] , 0 , tab_parm[0]->size );
  2253. X        break;
  2254. X
  2255. X        case AVERAGE_FUN :
  2256. X        value = average_fun ( tab_parm[0] , 0 , tab_parm[0]->size );
  2257. X        break;
  2258. X
  2259. X        case LOG_FUN :
  2260. X        value = log10 ( var_parm[0] );
  2261. X        break;
  2262. X        
  2263. X        case LN_FUN :
  2264. X        value = log ( var_parm[0] );
  2265. X        break;
  2266. X
  2267. X        case EXP_FUN :
  2268. X        value = exp ( var_parm[0] );
  2269. X        break;
  2270. X        
  2271. X        case POWER_FUN :
  2272. X        value = pow ( var_parm[0] , var_parm[1] );
  2273. X        break;
  2274. X        
  2275. X        case SQRT_FUN :
  2276. X        value = sqrt ( var_parm[0] );
  2277. X        break;
  2278. X        
  2279. X        case FLOOR_FUN :
  2280. X        value = floor ( var_parm[0] );
  2281. X        break;
  2282. X        
  2283. X        case CEIL_FUN :
  2284. X        value = ceil ( var_parm[0] );
  2285. X        break;
  2286. X        
  2287. X        case ABS_FUN :
  2288. X        value = fabs ( var_parm[0] );
  2289. X        break;
  2290. X        
  2291. X        case SIN_FUN :
  2292. X        value = sin ( var_parm[0] );
  2293. X        break;
  2294. X
  2295. X        case COS_FUN :
  2296. X        value = cos ( var_parm[0] );
  2297. X        break;
  2298. X
  2299. X        case ASIN_FUN :
  2300. X        value = asin ( var_parm[0] );
  2301. X        break;
  2302. X
  2303. X        case ACOS_FUN :
  2304. X        value = acos ( var_parm[0] );
  2305. X        break;
  2306. X
  2307. X        case ATAN_FUN :
  2308. X        value = atan ( var_parm[0] );
  2309. X        break;
  2310. X
  2311. X        case ATAN2_FUN :
  2312. X        value = atan2 ( var_parm[0] , var_parm[1] );
  2313. X        break;
  2314. X
  2315. X        case SINH_FUN :
  2316. X        value = sinh ( var_parm[0] );
  2317. X        break;
  2318. X
  2319. X        case COSH_FUN :
  2320. X        value = cosh ( var_parm[0] );
  2321. X        break;
  2322. X
  2323. X        case TANH_FUN :
  2324. X        value = tanh ( var_parm[0] );
  2325. X        break;
  2326. X
  2327. X        case HYPOT_FUN :
  2328. X        value = hypot ( var_parm[0] , var_parm[1] );
  2329. X        break;
  2330. X
  2331. X        case J0_FUN :
  2332. X        value = sin ( var_parm[0] );
  2333. X        break;
  2334. X
  2335. X        case J1_FUN :
  2336. X        value = j1 ( var_parm[0] );
  2337. X        break;
  2338. X
  2339. X        case JN_FUN :
  2340. X        value = jn ( var_parm[0] );
  2341. X        break;
  2342. X
  2343. X        case Y0_FUN :
  2344. X        value = y0 ( var_parm[0] );
  2345. X        break;
  2346. X
  2347. X        case Y1_FUN :
  2348. X        value = y1 ( var_parm[0] );
  2349. X        break;
  2350. X
  2351. X        case YN_FUN :
  2352. X        value = yn ( var_parm[0] );
  2353. X        break;
  2354. X
  2355. X        default :
  2356. X        value = eval ( table , row , dec[i].expr );
  2357. X        break;
  2358. X        }
  2359. X        return ( value );
  2360. X    }
  2361. X    }
  2362. X    abort ( "Undefined function '%s' referenced" , name );
  2363. X}
  2364. X
  2365. X
  2366. Xtable_st *
  2367. Xcall_tab_fun ( name , parm_list , table , row )
  2368. Xchar *name;
  2369. Xparm_st *parm_list;
  2370. Xtable_st *table;
  2371. Xint row;
  2372. X{
  2373. X    int i;
  2374. X    table_st *newtab;
  2375. X    parm_st *p1 , *p2;
  2376. X
  2377. X    for ( i = 0; i < num_dec; i++ ) {
  2378. X    if ( strcmp ( dec[i].name , name ) == 0 ) {
  2379. X        if ( dec[i].tab_expr == NULL )
  2380. X        abort ( "table function with no expression found" );
  2381. X        p1 = parm_list;
  2382. X        p2 = dec[i].parm_list;
  2383. X        while ( p1 != NULL  &&  p2 != NULL ) {
  2384. X        if ( p1->parm_type != p2->parm_type )
  2385. X            abort ( "type mismatch for parameter to function '%s'" , name );
  2386. X        if ( p1->parm_type == TABLE )
  2387. X            tab_declare ( p2->ident , eval_tab ( p1->tab_expr ) );
  2388. X        else
  2389. X            var_declare ( p2->ident , eval ( table , row , p1->expr ) );
  2390. X        p1 = p1->next;
  2391. X        p2 = p2->next;
  2392. X        }
  2393. X        if ( p1 != NULL  ||  p2 != NULL )
  2394. X        abort ( "illegal parameter list for function '%s'" , name );
  2395. X        newtab = eval_tab ( dec[i].tab_expr );
  2396. X        return ( newtab );
  2397. X    }
  2398. X    }
  2399. X    abort ( "Undefined function '%s' referenced" , name );
  2400. X}
  2401. X
  2402. X
  2403. X
  2404. Xis_fvar_ident ( name )
  2405. Xchar *name;
  2406. X{
  2407. X    int i;
  2408. X
  2409. X    for ( i = 0; i < num_dec; i++ ) {
  2410. X    if ( strcmp ( dec[i].name , name ) == 0 ) {
  2411. X        return ( dec[i].expr != NULL );
  2412. X    }
  2413. X    }
  2414. X    return ( 0 );
  2415. X}
  2416. X
  2417. X
  2418. X
  2419. Xis_ftab_ident ( name )
  2420. Xchar *name;
  2421. X{
  2422. X    int i;
  2423. X
  2424. X    for ( i = 0; i < num_dec; i++ ) {
  2425. X    if ( strcmp ( dec[i].name , name ) == 0 ) {
  2426. X        return ( dec[i].expr == NULL );
  2427. X    }
  2428. X    }
  2429. X    return ( 0 );
  2430. X}
  2431. X
  2432. X
  2433. X
  2434. Xcheck_group_fun ( name )
  2435. Xchar *name;
  2436. X{
  2437. X    int i;
  2438. X
  2439. X    for ( i = 0; i < num_dec; i++ ) {
  2440. X    if ( strcmp ( dec[i].name , name ) == 0 ) {
  2441. X        if ( dec[i].expr == NULL )
  2442. X        abort ( "function '%s' must return a value" , name );
  2443. X        if ( dec[i].parm_list == NULL
  2444. X        ||   dec[i].parm_list->next != NULL
  2445. X        ||   dec[i].parm_list->parm_type != TABLE )
  2446. X        abort ( "function '%s' expects a single table as parameters" );
  2447. X        return;
  2448. X    }
  2449. X    }
  2450. X}
  2451. SHAR_EOF
  2452. if test 9436 -ne "`wc -c < 'fundeclr.c'`"
  2453. then
  2454.     echo shar: error transmitting "'fundeclr.c'" '(should have been 9436 characters)'
  2455. fi
  2456. fi
  2457. # end of shell archive
  2458. exit 0
  2459.